package com.xianggu.protocol;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xianggu.mybatis.headlerImpl.TypeHandlerUtils;
import com.xianggu.mybatis.utils.TypeHandler;
import com.xianggu.spring.XiangGuApplicationContent;
import com.xianggu.spring.annotation.*;
import com.xianggu.spring.enums.HttpEnum;
import org.apache.commons.io.IOUtils;
import org.springframework.util.AntPathMatcher;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author chengjy
 * @date 2025/3/8
 */
public class HttpServletHandler {
    private XiangGuApplicationContent applicationContent;

    public HttpServletHandler(XiangGuApplicationContent applicationContent) {
        this.applicationContent = applicationContent;
    }

    public void handler(HttpServletRequest req, HttpServletResponse resp) {
        StringBuilder errMessage = new StringBuilder();
        // 这里完成请求的处理逻辑：主要执行本地方法
        try {

            ServletInputStream inputStream = req.getInputStream();
            Map<String, String[]> parameterMap = req.getParameterMap();
            Map<String, Object> paramMap = toParamMap(parameterMap);
            String json = IOUtils.toString(inputStream);

            String method = req.getMethod();
            // [, user, get/hhh/ddd]
            String[] split = req.getRequestURI().split("/",3);
            if(split.length < 3 ){
                throw new RuntimeException("请求路径错误");
            }
            String url = split[1];
            String path = "/" + split[2];

            Object bean = applicationContent.getContBeanMap().get(url);
            Class<?> aClass = bean.getClass();
            // 需要执行的方法
            Method targetMethod = null;

            // 获取路径传参
            Map<String, String> pathVariableMap = null;
            // Spring 提供的 AntPathMatcher 支持通配符匹配，适合处理动态路径模板。
            AntPathMatcher matcher = new AntPathMatcher();

            for (Method declaredMethod : aClass.getDeclaredMethods()) {
                // 校验请求方式
                String value = verifyTheRequestMethod(declaredMethod , method);
                if(value != null) { // 校验通过{}
                    if (value.equals(path)) {
                        targetMethod = declaredMethod;
                        break;
                    }else if( matcher.match(value, path) ){ // 前缀匹配上了说明是 @pathVariable
                        // 提取路径参数（返回 Map<String, String>）
                        pathVariableMap = matcher.extractUriTemplateVariables(value, path);
                        targetMethod = declaredMethod;
                        break;
                    }
                }
            }
            if(targetMethod != null){
                targetMethod.setAccessible(true);
                // 返回结果
                Object invokeValue = null;
                // 判断方法有没有入参
                Parameter[] parameters = targetMethod.getParameters();
                Object[] args = new Object[parameters.length];

                for (int i = 0; i < parameters.length; i++) {
                    Parameter parameter = parameters[i];
                    Class<?> type = parameter.getType();
                    // 路径传参
                    if (parameter.isAnnotationPresent( RequestParam.class)) {
                        // 如果接参是一个Map则特殊处理
                        if( Map.class.equals(type) && parameters.length == 1){
                            args[i] = paramMap;
                            // 结束参数处理
                            break;
                        }
                        RequestParam annotation = parameter.getAnnotation(RequestParam.class);
                        String paramName = annotation.value();
                        // 从解析的参数中获取
                        Object paramValue = paramMap.getOrDefault(paramName, null);
                        TypeHandler typeHandler = TypeHandlerUtils.getTypeHandler(type);
                        args[i] = paramValue != null ? typeHandler.toBaseType(paramValue) : null;
                    }else if(parameter.isAnnotationPresent( RequestBody.class)){
                        // 请求体传参
                        if( json == null){
                            errMessage.append("请求体为空！请检查 \r\n");
                        }
                        // 将json 转成 对象
                        Object object = JSONObject.parseObject(json, type);
                        args[i] = object;
                    }else if(parameter.isAnnotationPresent( PathVariable.class)){
                        PathVariable annotation = parameter.getAnnotation(PathVariable.class);
                        String paramName = annotation.value();
                        Object paramValue = pathVariableMap.get(paramName);
                        // 从解析的参数中获取
                        if( paramValue == null){
                            errMessage.append("PathVariable 路径参数为空！请检查 \r\n");
                        }
                        TypeHandler typeHandler = TypeHandlerUtils.getTypeHandler(type);
                        args[i] = paramValue != null ? typeHandler.toBaseType(paramValue) : null;
                    } else{
                        Object paramValue = paramMap.values().stream().findFirst().orElse(null);
                        // 没有param注解，无法获取对应的入参属性名，随机取一个返回
                        args[i] = String.class.equals( type)? String.valueOf(paramValue) : paramValue;
                    }
                }

                if (parameters.length == 0) {
                    invokeValue = targetMethod.invoke(bean);
                }else{
                    //组装参数
                    invokeValue = targetMethod.invoke(bean , args);
                }

                if(invokeValue == null){
                    invokeValue = "";
                }
                resp.getOutputStream().write(JSON.toJSONString(invokeValue).getBytes(StandardCharsets.UTF_8));
            }else{
                resp.getOutputStream().write("404 访问资源不存在".getBytes(StandardCharsets.UTF_8));
            }
            return;
        } catch (IOException e) {
            e.printStackTrace();
            errMessage.append(e.getMessage() + e.getCause());
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            errMessage.append(e.getMessage() + e.getCause());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            errMessage.append(e.getMessage() + e.getCause());
        }
        try {
            resp.getOutputStream().write(errMessage.toString().getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
    //校验请求方式是否匹配
    private String verifyTheRequestMethod(Method declaredMethod, String method) {
        String value = null;
        if (HttpEnum.GET.equals(method) && declaredMethod.isAnnotationPresent(GetMapping.class)) {
            GetMapping annotation = declaredMethod.getAnnotation(GetMapping.class);
            value = annotation.value();
        }else if (HttpEnum.POST.equals(method) && declaredMethod.isAnnotationPresent(PostMapping.class)) {
            PostMapping annotation = declaredMethod.getAnnotation(PostMapping.class);
            value = annotation.value();
        }else if (HttpEnum.DELETE.equals(method) && declaredMethod.isAnnotationPresent(DeleteMapping.class)) {
            DeleteMapping annotation = declaredMethod.getAnnotation(DeleteMapping.class);
            value = annotation.value();
        }else if (HttpEnum.PUT.equals(method) && declaredMethod.isAnnotationPresent(PutMapping.class)) {
//            PutMapping annotation = declaredMethod.getAnnotation(PutMapping.class);
//            value = annotation.value();
        }
        return value;
    }

    private Map<String, Object> toParamMap(Map<String, String[]> parameterMap) {
        Map<String, Object> paramMap = new HashMap<>(parameterMap.size());

        parameterMap.forEach( (key,value)->{
            if(value.length > 1){
                // 不排除前端传递数组的可能
                paramMap.put(key, value);
            }else {
                paramMap.put(key, value[0]);
            }
        });
        return paramMap;
    }
}
